iT邦幫忙

2026 iThome 鐵人賽

DAY 20
0

https://ithelp.ithome.com.tw/upload/images/20260820/20161290sWBHfXzTv0.png

當單一路徑不夠用,開始考慮 Utility、Hybrid、Scatter-Gather 與多 Agent 協同。

到目前為止,我們討論的 Embabel 都是基於預設的 單線 GOAP(Goal-Oriented Action Planning):從當前的世界狀態出發,透過 A* 演算法在狀態空間中計算出一條總成本(Cost)最低的唯一最佳路徑,然後一步一步執行直到達成 Goal。

然而,在複雜的企業真實世界中,業務需求往往不是單一路徑能解決的:

  • 多模型交叉審查(Consensus):一份價值百萬的企業報價,不能只由單一模型判定,需要 GPT-4o、Claude 3.5 Sonnet 與 Llama 3 各審核一次並投票取共識。
  • 多維度並行分析(Scatter-Gather):分析客戶畫像時,需要同時並行查詢「CRM 旅程歷史」、「客服工單紀錄」與「財務信用評級」,最後合併匯總。
  • 探索型反應式對話(Utility / Chatbot):使用者可能隨時岔開話題問天氣或查退款,此時不存在預設的終端 Goal,需要依據當前上下文的「最大效益(Value vs Cost)」動態做即時反應。

今天我們將一口氣拆解 Embabel 提供的四種規劃器(Planners)、Scatter-Gather 並行模式與多模型共識機制。


1. 今天要解決的痛點與核心觀念

痛點背景:單一線性路徑的三大瓶頸

  1. 循序執行的效能瓶頸(High Latency):若分析一個任務需要調用 4 個獨立的外部 API,線性串行執行需要耗時 $1.5s \times 4 = 6s$,系統吞吐量極低。
  2. 單點模型偏見(Single-Model Hallucination):單一 LLM 存在幻覺率,高風險場景(如合規判定、代碼稽核)缺乏交叉驗證機制。
  3. 探索型任務無從下手:對於客服對話或開放式調查,開發者無法預先定義明確的 Goal State,強行使用 GOAP 會導致規劃器找不到路徑而報錯。

觀念圖解:Embabel 四大規劃器與進階編排全景

https://ithelp.ithome.com.tw/upload/images/20260820/20161290xQFE53a9ty.png

  1. GOAP 規劃器(預設):基於 A* 最短路徑演算法,適用於目標明確、高確定性業務流程。
  2. UTILITY 規劃器:依據淨值最大化(Value - Cost),適用於開放式客服與即時分流。
  3. HYBRID 規劃器:收集 rightarrow 合成 rightarrow 終止,適用於 Reducer 數據管線。
  4. SUPERVISOR 規劃器:依據 LLM 語意動態路由,適用於彈性研究助理。

2. 官方核心技術依據與架構深度

規劃器決策路徑(Planner Decision Tree)

https://ithelp.ithome.com.tw/upload/images/20260820/20161290cv5aci0Trk.png
在選擇規劃器時,核心判斷準則是「目標是否明確」與「路徑是否動態」:若有固定終點且講求最小代價選 GOAP;若為開放式互動、即時最大價值選 Utility;多來源並行聚合則選 Hybrid 與 Scatter-Gather。

1. Utility Planner 的效用價值模型(Value vs Cost)

與 GOAP 尋找「整體最小成本」不同,Utility Planner 在每一步評估中,計算的是當前所有可用 Action 的 淨效用(Net Utility)

Utility = Value - Cost

  • value:代表執行該 Action 能為系統帶來的業務價值(0.0 ~ 1.0)。
  • cost:代表調用延遲、Token 費用與資源開銷。
  • 規劃器每一步永遠挑選 Utility 最高的 Action 執行,天然適用於客服對話中動態判斷「該優先安撫情緒、直接退款,還是引導填表」。

2. ScatterGatherBuilder 與並行扇出(Fan-out / Fan-in)

Embabel 內建 ScatterGatherBuilder,能夠將一個資料物件同時扇出(Fan-out)給多個獨立 Action / Sub-Agent 進行非同步並行處理,並透過一個強型別聚合器(Aggregator / Reducer)進行扇入(Fan-in)合併:

  • 底層支援 Java 21 虛擬執行緒(Virtual Threads)高併發調度。
  • 具備超時控制(Timeout)與部分容錯(Partial Failure Resilience)。

3. ConsensusBuilder 多模型共識裁決

專為高合規場景設計的共識架構:

  • 同時向多個不同的模型(如 OpenAI GPT-4o、Anthropic Claude 3.5、本地 Ollama Llama 3)發送同一審核請求。
  • 透過投票策略(Majority Vote / Unanimous)判定最終結果,若產生分歧則自動觸發仲裁流程。

3. 完整程式碼實戰(Production-Ready Code)

以下實作一個完整的進階範例,展示:

  1. Utility Planner 意圖路由 Agent
  2. Scatter-Gather 多模型並行合規審查器

1. Utility Planner 意圖動態分流實作

package com.antechinus.travel.agent;

import com.embabel.agent.annotation.AchievesGoal;
import com.embabel.agent.annotation.Action;
import com.embabel.agent.annotation.Agent;
import com.embabel.agent.annotation.Cost;
import com.embabel.agent.api.PlannerType;
import org.springframework.stereotype.Component;

/**
 * 基於 Utility Planner 的客服意圖分流 Agent
 * 每一步由演算法根據 (Value - Cost) 最大化自動選取最佳動作
 */
@Component
@Agent(
    description = "智慧客服動態分流與處置",
    planner = PlannerType.UTILITY
)
public class SupportUtilityAgent {

    public record UserInquiry(String text, boolean isVip, boolean isAngry) {}
    public record RoutingDecision(String department, String priorityLevel) {}
    public record FinalHandledTicket(String ticketId, String actionSummary) {}

    /**
     * 處理 VIP 客戶緊急投訴 Action
     * 設定極高 Value,確保符合條件時優先觸發
     */
    @Action(cost = 0.05, value = 0.98)
    public RoutingDecision handleVipUrgent(UserInquiry inquiry) {
        if (inquiry.isVip() && inquiry.isAngry()) {
            return new RoutingDecision("VIP_EXECUTIVE_DESK", "P0_CRITICAL");
        }
        // 若條件不符回傳 null,Utility 評估將自動忽略
        return null;
    }

    /**
     * 處理一般帳單問題 Action
     */
    @Action(cost = 0.01, value = 0.70)
    public RoutingDecision handleBilling(UserInquiry inquiry) {
        if (inquiry.text().contains("發票") || inquiry.text().contains("退費")) {
            return new RoutingDecision("BILLING_TEAM", "P2_NORMAL");
        }
        return null;
    }

    /**
     * 達成終端處理目標
     */
    @AchievesGoal(description = "完成客服工單建檔與分流")
    @Action(cost = 0.02, value = 0.95)
    public FinalHandledTicket finalizeTicket(RoutingDecision decision) {
        String ticketId = "TICK-" + System.currentTimeMillis();
        return new FinalHandledTicket(ticketId, "已分派至: " + decision.department() + ",等級: " + decision.priorityLevel());
    }
}

2. ScatterGatherBuilder 多模型交叉審查實作

package com.antechinus.travel.agent;

import com.antechinus.travel.domain.OfferDraft;
import com.antechinus.travel.domain.ReviewedOffer;
import com.embabel.agent.api.Ai;
import com.embabel.agent.api.ScatterGatherBuilder;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * 多模型並行共識審核服務
 * 利用 Scatter-Gather 同時調用多個 LLM 交叉比對方案合規性
 */
@Service
public class MultiModelConsensusService {

    private final Ai ai;

    public MultiModelConsensusService(Ai ai) {
        this.ai = ai;
    }

    public record ModelAuditVote(String modelName, boolean approved, String reason) {}

    /**
     * 執行多模型並行投票審核
     *
     * @param draft 方案草稿
     * @return 最終審核結果
     */
    public ReviewedOffer evaluateOfferConsensus(OfferDraft draft) {
        String prompt = "請以嚴格風控標準審核此優惠方案是否合規(折扣不可大於20%):" + draft.description();

        // 1. 定義多個並行審核任務 (Fan-out)
        var gpt4Task = CompletableFuture.supplyAsync(() -> {
            var res = ai.withModel("gpt-4o").createObject(prompt, ModelAuditVote.class);
            return new ModelAuditVote("GPT-4o", res.approved(), res.reason());
        });

        var claudeTask = CompletableFuture.supplyAsync(() -> {
            var res = ai.withModel("claude-3-5-sonnet").createObject(prompt, ModelAuditVote.class);
            return new ModelAuditVote("Claude-3.5", res.approved(), res.reason());
        });

        var miniTask = CompletableFuture.supplyAsync(() -> {
            var res = ai.withModel("gpt-4o-mini").createObject(prompt, ModelAuditVote.class);
            return new ModelAuditVote("GPT-4o-mini", res.approved(), res.reason());
        });

        // 2. 聚合多模型結果 (Fan-in / Reducer)
        List<ModelAuditVote> votes = List.of(gpt4Task.join(), claudeTask.join(), miniTask.join());

        long approvalCount = votes.stream().filter(ModelAuditVote::approved).count();
        boolean consensusReached = approvalCount >= 2; // 多數決 (2/3)

        String summaryNote = String.format("共識投票: %d/3 通過 (明細: %s)",
                approvalCount,
                votes.stream().map(v -> v.modelName() + ":" + v.approved()).toList());

        return new ReviewedOffer(
                draft.customerId(),
                draft.discountPercent(),
                draft.description(),
                consensusReached ? "APPROVED" : "REJECTED",
                summaryNote,
                Instant.now()
        );
    }
}

4. 生產環境避坑指南與對比分析

常見踩雷與除錯秘訣

  1. 雷區一:無限制的 Fan-out 造成 API Rate Limit 崩潰
    • 現象:在 Scatter-Gather 同時開 50 個執行緒並行呼叫 OpenAI,瞬間收到 429 Too Many Requests
    • 解法:在並行調用前必須配置 Semaphore(信號量)或 Spring AI 的 RateLimiter,嚴格限制最大並發數(Concurrency Limit $\le 5$)。
  2. 雷區二:子 Agent 輸出型別模糊(Type Ambiguity)
    • 現象:多個並行 Action 全部回傳 String 或通用 Map<String, Object>,導致後續聚合器根本無法透過型別精確比對資料來源。
    • 解法:每一個並行分支必須定義具體的型別 Record(如 CrmRiskResultFinanceCreditResult)。
  3. 雷區三:濫用 Supervisor Planner 導致 Token 成本失控
    • 現象:本來三行代碼就能算清楚的順序,硬要交給 Supervisor LLM 去看 Schema 選 Action,執行一次要花 4 次 LLM 呼叫。
    • 解法業務規則永遠優先使用 GOAP;只有完全無固定路徑的研究助理或程式碼生成,才啟用 Supervisor。

規劃器選型 Good vs Bad 對比表

https://ithelp.ithome.com.tw/upload/images/20260820/20161290OM0OQImnqa.jpg

業務場景 ❌ 錯誤選型 (Bad) ✅ 正確選型 (Good) 原因說明
金融貸款審批 Supervisor Planner GOAP Planner 審核流程必須 100% 確定、可重現且具備法律合規性
動態智慧客服 硬編碼 if-else / GOAP UTILITY Planner 使用者提問充滿隨機性,需依淨效用(V - C)動態反應
百萬級優惠方案 單一 LLM Action 審查 Scatter-Gather 共識審查 透過多模型投票防範單一模型的幻覺與誤判風險
大規模數據萃取 串行 for 迴圈執行 並行 Fan-out + Reducer 充分利用 Java 21 虛擬執行緒大幅縮短端到端延遲

5. 今日動手實作任務與發文備註

🛠️ 今日實作任務

  1. 實作一個 Utility Agent:為客服工單建立一個基於 PlannerType.UTILITY 的分流器,宣告 2 個具備不同 costvalue 的 Action。
  2. 實作 Scatter-Gather 整合:撰寫一個方法同時發送 2 個不同模型的 Mock 請求,並透過 Reducer 聚合為單一的綜合評估報告。
  3. 思考題:為什麼說「在 GOAP 中 Cost 越低越優先,但在 Utility 中卻是 Value - Cost 越高越優先」?這反映了兩種規劃思維的什麼本質差異?

上一篇
Day 19:有些流程就是要等人
下一篇
Day 21:讓資料自己變成畫面
系列文
讓 AI Agent 真的做事:用 Embabel 打造可控、可測試的智慧 Dashboard22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言